<?php

use Carbon\Carbon as Carbon;

class CronController extends BaseController {

  private $_reddit;

  const BLOCKSIZE     = 15;
  const TIMELIMITDAYS = 14; // make timeline for last X days.

  public function runCron() {
    echo '<pre>';
    $this->runGetComments();
    $this->runComments();
    $this->runTimelines();
    exit;
  }

  public function runGetComments() {
    $this->_reddit = App::make('reddit');
    $this->_getCommentsFromUsers();
  }

  public function runComments() {
    $this->_updateCommentTimes();
  }

  public function runTimelines() {
    $this->_createTimelines();
  }

  private function _getCommentsFromUsers() {
    $this->_debug('_getCommentsFromUsers() start');
    $users = Redditor::where(
                            function($query) {
                              $query->where('userexists', '=', 1)->orWhereNull('userexists');
                            })->
                                    where('complete','=',0)->
                    orderBy('updated_at', 'ASC')->take(5)->get();


    // got to login!
    $result = $this->_reddit->login(Config::get('reddit.username'), Config::get('reddit.password'));
    if ($result === false) {
      Log::debug('Some JSON error I guess. ' . print_r($result, true));
      return App::abort(500);
    }

    // loop over users.
    foreach ($users as $user) {
      $this->_debug('Now at user ' . $user->username);
      $user->touch();

      // does the user even exist?
      if (is_null($user->userexists)) {
        $this->_debug('Try to find out if user exists...');
        $exists           = $this->_reddit->userExists($user->username);
        $user->userexists = $exists ? 1 : 0;
        $user->save();
      }
      // if so:
      if ($user->userexists == 1) {
        $this->_debug('Now working on user ' . $user->username);

        // we always get posts:
        $getPosts = true;

        // user complete means a day's break.
        if ($user->complete == 1) {
          $now  = new Carbon();
          $diff = $now->diff(Carbon::createFromTimestampUTC(strtotime($user->updated_at)));
          if ($diff->days < 1) {
            $this->_debug('Skipped over ' . $user->username.' because complete.');
            continue;
          }
        }

        if ($getPosts) {
          $this->_debug('Finding posts for ' . $user->username . ': [' . $user->before . '/' . $user->after . ']');

          $last = false;
          if (is_null($user->before) && !is_null($user->after)) {
            // probably last page:
            $last = true;
            $this->_debug('last = true');
          }

          $comments_raw = $this->_reddit->getComments($user->username, $user->before, $user->after);

          if (count($comments_raw['comments']) > 0) {
            // update user information from this array.

            $user->before = $comments_raw['meta']['before'];
            $user->after  = $comments_raw['meta']['after'];
            $this->_debug('Found ' . count($comments_raw['comments']) . ' comments');
            $this->_debug('Update before and after to [' . $user->before . '/' . $user->after . ']');
            $user->save();

            // process the comments
            $saved = 0;
            foreach ($comments_raw['comments'] as $c) {
              $comment              = new Comment;
              $comment->redditor_id = $user->id;
              $comment->text        = $c['text'];
              $comment->enddate     = $c['created']->format('Y-m-d');
              $comment->endtime     = $c['created']->format('H:i:s');
              $comment->day         = intval($c['created']->format('w'));
              $comment->comment_id  = $c['comment_id'];
              $comment->link_id     = $c['link_id'];
              $comment->subreddit   = $c['subreddit'];
              $validator            = Validator::make($comment->toArray(), Comment::$rules);
              if (!$validator->fails()) {
                $this->_debug('Saved comment.');
                $comment->save();
                $saved++;
              } else {
                $this->_debug('DOUBLE comment!');
              }
            }
            $this->_debug('Saved ' . $saved . ' comments');
            if ($last && $saved == 0) {
              $user->complete = 1;
            }
            $user->save();
          } else {
            $this->_debug('Did not find comments.');
          }
        }
      } else {
        $this->_debug('Doesnt even exist.');
      }
    }
    $this->_debug('_getCommentsFromUsers() end');
  }

  private function _updateCommentTimes() {
    $this->_debug('_updateCommentTimes() start');
    $comments = Comment::whereNull('length')->where('startdate', '=', '0000-00-00')->get();
    $this->_debug('Processing ' . count($comments) . ' comments.');
    foreach ($comments as $c) {
      $c->length    = str_word_count(strip_tags($c->text));
      // typing speed is 35 words per minute (http://en.wikipedia.org/wiki/Words_per_minute).
      $minutes      = floor($c->length / 35) == 0 ? 1 : floor($c->length / 35);
      $start        = Carbon::createFromFormat('Y-m-d H:i:s', $c->enddate . ' ' . $c->endtime);
      $start->subMinutes($minutes);
      $c->startdate = $start->format('Y-m-d');
      $c->starttime = $start->format('H:i:s');

      $c->save();
    }
    $this->_debug('Done processing!');
  }

  private function _createTimelines() {
    $users = Redditor::get();
    foreach ($users as $user) {
      // some debug:
      $this->_debug('Now creating timeline for ' . $user->username);
      $this->_debug('Have ' . $user->comments()->count() . ' TOTAL  comments');

      // now some graphical data:
      $data = array(
          'cols' => array(
              array(
                  'id'    => 'day',
                  'label' => 'Day of the week',
                  'type'  => 'string',
                  'p'     => array('role' => 'domain')
              ),
              array(
                  'id'    => 'tod',
                  'label' => 'Time of day',
                  'type'  => 'string',
                  'p'     => array('role' => 'domain')
              ),
              array(
                  'id'    => 'start',
                  'label' => 'Start',
                  'type'  => 'date',
                  'p'     => array('role' => 'data')),
              array(
                  'id'    => 'end',
                  'label' => 'End',
                  'type'  => 'date',
                  'p'     => array('role' => 'data')),
          ),
          'rows' => array()
      );

      $index           = 0;
      $timeLimit       = new Carbon();
      $timeLimit->subDays(self::TIMELIMITDAYS);
      $timeLimitString = $timeLimit->format('Y-m-d');
      for ($day = 0; $day < 7; $day++) {
        // some initializing variables:
        $start    = new Carbon();
        $start->modify('midnight');
        $tomorrow = clone $start;
        $tomorrow->addDay();

        while ($start < $tomorrow) {
          $end = clone $start;
          $end->addMinutes(self::BLOCKSIZE);


          $startString = $start->format('H:i:s');
          $end->subMinute();
          $endString   = $end->format('H:i:s');
          $comments    = $user->comments()
                  ->where('day', '=', $day)
                  ->where('startdate', '>=', $timeLimitString)
                  ->where('startdate', '=', DB::Raw('`enddate`'))
                  ->where('starttime', '<=', DB::Raw('`endtime`'))
                  ->where(function($query) use ($startString, $endString) {
                            $query->where(function($query) use ($startString, $endString) {
                                      $query->where('starttime', '>=', DB::Raw('CAST("' . $startString . '" AS time)'));
                                      $query->where('starttime', '<=', DB::Raw('CAST("' . $endString . '" AS time)'));
                                    });
                            $query->orWhere(function($query) use ($startString, $endString) {
                                      $query->where('endtime', '>=', DB::Raw('CAST("' . $startString . '" AS time)'));
                                      $query->where('endtime', '<=', DB::Raw('CAST("' . $endString . '" AS time)'));
                                    });
                            // outside both
                            $query->orWhere(function($query) use ($startString, $endString) {
                                      $query->where('starttime', '<=', DB::Raw('CAST("' . $startString . '" AS time)'));
                                      $query->where('endtime', '>=', DB::Raw('CAST("' . $endString . '" AS time)'));
                                    });
                          })
                  ->get();
          //echo $user->id.': '.$day.' ['.$start->format('H:i:s').'/'.$end->format('H:i:s').']: '.count($comments).'<br>';
          if (count($comments) > 0) {
            // add rows to the data thing:
            $data['rows'][$index]['c'][0]['v'] = $this->_days[$day];
            $data['rows'][$index]['c'][1]['v'] = count($comments);
            if ($end->format('H:i:s') == '00:00:00') {
              $end->subMinute();
            }
            $data['rows'][$index]['c'][2]['v'] = 'Date(0,0,0,' . $start->format('H') . ',' . $start->format('i') . ',' . $start->format('s') . ')';
            $data['rows'][$index]['c'][3]['v'] = 'Date(0,0,0,' . $end->format('H') . ',' . $end->format('i') . ',' . $end->format('s') . ')';
            $index++;
            //$this->_debug($day . ': ' . count($comments) . ' comments between ' . $startString . ' and ' . $endString);
          }
          $start->addMinutes(self::BLOCKSIZE);
        }
      }
      $json           = json_encode($data);
      $user->timeline = $json;
      $user->save();
    }

  }

  private function _debug($str) {
    Log::debug($str);
    echo $str . "\n";
  }

}

?>
